package com.sunxboy.platform.thread;

import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;

import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

/**
 * Thread pool executor that blocks the caller until task can be executed. This prevents issue where you have n thread
 * available, while the thread responsible for populating the task queue is stuck execution long running task
 */
public class CallerblockingThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {
    private static final long serialVersionUID = 1L;

    public CallerblockingThreadPoolTaskExecutor(String threadFactoryName) {
        setThreadFactory(new NamedThreadFactory(threadFactoryName));
        super.setRejectedExecutionHandler(new QueuePopulatingExecutionHandler());
    }

    @Override
    public void setRejectedExecutionHandler(RejectedExecutionHandler rejectedExecutionHandler) {
        throw new UnsupportedOperationException("This task executor only support blocking the caller on queue overflow condition");
    }

    private class QueuePopulatingExecutionHandler implements RejectedExecutionHandler {
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            try {
                if (executor.isShutdown()) {
                    throw new RejectedExecutionException("Executor has been shutdown");
                }
                executor.getQueue().put(r);
            }
            catch (InterruptedException e) {
                throw new RejectedExecutionException("Interrupted while waiting for task queue to clear");
            }
        }

    }

}
